import mongoose from 'mongoose';
import { Role, IRole, IRoleDocument } from '../models/role';

/**
 * 角色数据访问对象
 * 提供角色相关的数据库操作方法
 */
export class RoleDAO {
  /**
   * 创建新角色
   * @param roleData 角色数据
   * @returns 创建的角色文档
   */
  async create(roleData: Partial<IRole>): Promise<IRoleDocument> {
    try {
      const role = new Role(roleData);
      return await role.save();
    } catch (error: any) {
      if (error.code === 11000) {
        // 处理唯一性约束错误
        const field = Object.keys(error.keyPattern)[0];
        throw new Error(`${field} already exists`);
      }
      throw error;
    }
  }

  /**
   * 根据ID查找角色
   * @param id 角色ID
   * @returns 角色文档或null
   */
  async findById(id: mongoose.Types.ObjectId | string): Promise<IRoleDocument | null> {
    try {
      if (!id) {
        throw new Error('Role ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid role ID format');
      }
      
      return await Role.findById(id).populate('systemId');
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据角色编码查找角色
   * @param code 角色编码
   * @returns 角色文档或null
   */
  async findByCode(code: string): Promise<IRoleDocument | null> {
    try {
      if (!code || typeof code !== 'string') {
        throw new Error('Invalid role code format');
      }
      return await Role.findByCode(code);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据角色名称查找角色
   * @param name 角色名称
   * @returns 角色文档或null
   */
  async findByName(name: string): Promise<IRoleDocument | null> {
    try {
      if (!name || typeof name !== 'string') {
        throw new Error('Invalid role name format');
      }
      return await Role.findByName(name);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据系统ID查找角色
   * @param systemId 系统ID
   * @returns 角色文档数组
   */
  async findBySystemId(systemId: mongoose.Types.ObjectId | string): Promise<IRoleDocument[]> {
    try {
      if (!systemId) {
        throw new Error('System ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(systemId)) {
        throw new Error('Invalid system ID format');
      }
      
      const objectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      return await Role.findBySystemId(objectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据角色级别查找角色
   * @param level 角色级别
   * @returns 角色文档数组
   */
  async findByLevel(level: number): Promise<IRoleDocument[]> {
    try {
      if (typeof level !== 'number' || level < 1) {
        throw new Error('Invalid role level');
      }
      return await Role.findByLevel(level);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据状态查找角色
   * @param status 角色状态
   * @returns 角色文档数组
   */
  async findByStatus(status: number): Promise<IRoleDocument[]> {
    try {
      if (![0, 1].includes(status)) {
        throw new Error('Invalid role status');
      }
      return await Role.findByStatus(status);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 更新角色信息
   * @param id 角色ID
   * @param updateData 更新数据
   * @returns 更新后的角色文档或null
   */
  async update(
    id: mongoose.Types.ObjectId | string,
    updateData: Partial<IRole>
  ): Promise<IRoleDocument | null> {
    try {
      if (!id) {
        throw new Error('Role ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid role ID format');
      }
      
      // 移除不允许更新的字段
      const { createdAt, updatedAt, ...allowedUpdates } = updateData;
      
      const updatedRole = await Role.findByIdAndUpdate(
        id,
        allowedUpdates,
        { new: true, runValidators: true }
      ).populate('systemId');
      
      return updatedRole;
    } catch (error: any) {
      if (error.code === 11000) {
        // 处理唯一性约束错误
        const field = Object.keys(error.keyPattern)[0];
        throw new Error(`${field} already exists`);
      }
      throw error;
    }
  }

  /**
   * 删除角色
   * @param id 角色ID
   * @returns 是否删除成功
   */
  async delete(id: mongoose.Types.ObjectId | string): Promise<boolean> {
    try {
      if (!id) {
        throw new Error('Role ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid role ID format');
      }
      
      // 检查角色是否可以被删除
      const role = await Role.findById(id);
      if (!role) {
        throw new Error('Role not found');
      }
      
      const canBeDeleted = await role.canBeDeleted();
      if (!canBeDeleted) {
        throw new Error('Role cannot be deleted because it has associated users or permissions');
      }
      
      const result = await Role.findByIdAndDelete(id);
      return !!result;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取系统角色列表
   * @returns 系统角色文档数组
   */
  async getSystemRoles(): Promise<IRoleDocument[]> {
    try {
      return await Role.getSystemRoles();
    } catch (error) {
      throw error;
    }
  }

  /**
   * 检查角色编码是否存在
   * @param code 角色编码
   * @param excludeId 排除的角色ID（用于更新时检查）
   * @returns 是否存在
   */
  async isCodeExists(code: string, excludeId?: mongoose.Types.ObjectId | string): Promise<boolean> {
    try {
      if (!code || typeof code !== 'string') {
        throw new Error('Invalid role code format');
      }
      
      const excludeObjectId = excludeId && mongoose.Types.ObjectId.isValid(excludeId) 
        ? (typeof excludeId === 'string' ? new mongoose.Types.ObjectId(excludeId) : excludeId)
        : undefined;
      
      return await Role.isCodeExists(code, excludeObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 检查角色名称是否存在
   * @param name 角色名称
   * @param excludeId 排除的角色ID（用于更新时检查）
   * @returns 是否存在
   */
  async isNameExists(name: string, excludeId?: mongoose.Types.ObjectId | string): Promise<boolean> {
    try {
      if (!name || typeof name !== 'string') {
        throw new Error('Invalid role name format');
      }
      
      const excludeObjectId = excludeId && mongoose.Types.ObjectId.isValid(excludeId) 
        ? (typeof excludeId === 'string' ? new mongoose.Types.ObjectId(excludeId) : excludeId)
        : undefined;
      
      return await Role.isNameExists(name, excludeObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 批量创建角色
   * @param rolesData 角色数据数组
   * @returns 创建的角色文档数组
   */
  async batchCreate(rolesData: Partial<IRole>[]): Promise<IRoleDocument[]> {
    try {
      if (!Array.isArray(rolesData)) {
        throw new Error('Roles data must be an array');
      }
      
      if (rolesData.length === 0) {
        throw new Error('Roles data array cannot be empty');
      }
      
      // 验证每个角色数据的必填字段
      for (const roleData of rolesData) {
        if (!roleData.name || !roleData.code || typeof roleData.level !== 'number') {
          throw new Error('Missing required fields: name, code, and level are required');
        }
      }
      
      const createdRoles = await Role.insertMany(rolesData);
      return createdRoles as IRoleDocument[];
    } catch (error: any) {
      if (error.code === 11000) {
        throw new Error('Duplicate role code found in batch data');
      }
      throw error;
    }
  }

  /**
   * 更新角色状态
   * @param id 角色ID
   * @param status 新状态
   * @returns 更新后的角色文档或null
   */
  async updateStatus(id: mongoose.Types.ObjectId | string, status: number): Promise<IRoleDocument | null> {
    try {
      if (!id) {
        throw new Error('Role ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid role ID format');
      }
      
      if (![0, 1].includes(status)) {
        throw new Error('Invalid status value');
      }
      
      return await Role.findByIdAndUpdate(
        id,
        { status },
        { new: true, runValidators: true }
      ).populate('systemId');
    } catch (error) {
      throw error;
    }
  }

  /**
   * 查找所有角色（支持分页和筛选）
   * @param criteria 筛选条件
   * @param options 分页和排序选项
   * @returns 角色列表和分页信息
   */
  async findAll(
    criteria: {
      name?: string;
      code?: string;
      level?: number;
      systemId?: mongoose.Types.ObjectId | string;
      status?: number;
    } = {},
    options: {
      page?: number;
      limit?: number;
      sort?: string;
      select?: string;
    } = {}
  ): Promise<{ roles: IRoleDocument[]; total: number; page: number; totalPages: number }> {
    try {
      const {
        page = 1,
        limit = 10,
        sort = '-createdAt',
        select
      } = options;
      
      // 构建查询条件
      const query: any = {};
      
      if (criteria.name) {
        query.name = { $regex: criteria.name, $options: 'i' };
      }
      
      if (criteria.code) {
        query.code = { $regex: criteria.code, $options: 'i' };
      }
      
      if (typeof criteria.level === 'number') {
        query.level = criteria.level;
      }
      
      if (criteria.systemId) {
        if (!mongoose.Types.ObjectId.isValid(criteria.systemId)) {
          throw new Error('Invalid system ID format');
        }
        query.systemId = criteria.systemId;
      }
      
      if (typeof criteria.status === 'number') {
        if (![0, 1].includes(criteria.status)) {
          throw new Error('Invalid status value');
        }
        query.status = criteria.status;
      }
      
      // 计算跳过的文档数量
      const skip = (page - 1) * limit;
      
      // 构建查询
      let roleQuery = Role.find(query)
        .populate('systemId')
        .sort(sort)
        .skip(skip)
        .limit(limit);
      
      if (select) {
        roleQuery = roleQuery.select(select);
      }
      
      // 执行查询
      const [roles, total] = await Promise.all([
        roleQuery.exec(),
        Role.countDocuments(query)
      ]);
      
      const totalPages = Math.ceil(total / limit);
      
      return {
        roles,
        total,
        page,
        totalPages
      };
    } catch (error) {
      throw error;
    }
  }
}

export default RoleDAO;